﻿using System;
using System.Collections.Generic;
using System.Text;

namespace UAC.Operation
{
    public class UACOp
    {

        public static bool CanRead(string idPeople, int operationdefid, Dictionary<string, object> content)
        {
            try
            {
                ControlCondition condition = Utils.GetControlCondition(operationdefid);
                return canRead(idPeople, condition, content);
            }
            catch
            {
                return false;
            }
        }

        public static bool CanEdit(string idPeople, int operationdefid, Dictionary<string, object> content, Dictionary<string, object> newContent)
        {
            try
            {
                ControlCondition condition = Utils.GetControlCondition(operationdefid);
                return canRead(idPeople, condition, content) && canRead(idPeople, condition, newContent);
            }
            catch
            {
                return false;
            }
        }

        #region Private
        private static bool compareValues(object val1, object val2, CompareType compareType, ParamType paramType)
        {
            switch (compareType)
            {
                case CompareType.Equal:
                    {
                        switch (paramType)
                        {
                            case ParamType.Date:
                                return Convert.ToDateTime(val1) == Convert.ToDateTime(val2);
                            case ParamType.Number:
                                return Convert.ToInt64(val1) == Convert.ToInt64(val2);
                            case ParamType.String:
                                return val1.ToString() == val2.ToString();
                        }
                    }
                    break;
                case CompareType.Greater:
                    {
                        switch (paramType)
                        {
                            case ParamType.Date:
                                return Convert.ToDateTime(val1) > Convert.ToDateTime(val2);
                            case ParamType.Number:
                                return Convert.ToInt64(val1) > Convert.ToInt64(val2);
                        }
                    }
                    break;
                case CompareType.GreaterOrEqual:
                    {
                        switch (paramType)
                        {
                            case ParamType.Date:
                                return Convert.ToDateTime(val1) >= Convert.ToDateTime(val2);
                            case ParamType.Number:
                                return Convert.ToInt64(val1) >= Convert.ToInt64(val2);
                        }
                    }
                    break;
                case CompareType.Less:
                    {
                        switch (paramType)
                        {
                            case ParamType.Date:
                                return Convert.ToDateTime(val1) < Convert.ToDateTime(val2);
                            case ParamType.Number:
                                return Convert.ToInt64(val1) < Convert.ToInt64(val2);
                        }
                    }
                    break;
                case CompareType.LessOrEqual:
                    {
                        switch (paramType)
                        {
                            case ParamType.Date:
                                return Convert.ToDateTime(val1) <= Convert.ToDateTime(val2);
                            case ParamType.Number:
                                return Convert.ToInt64(val1) <= Convert.ToInt64(val2);
                        }
                    }
                    break;
                case CompareType.Unequal:
                    {
                        switch (paramType)
                        {
                            case ParamType.Date:
                                return Convert.ToDateTime(val1) != Convert.ToDateTime(val2);
                            case ParamType.Number:
                                return Convert.ToInt64(val1) != Convert.ToInt64(val2);
                            case ParamType.String:
                                return val1.ToString() != val2.ToString();
                        }
                    }
                    break;
            }
            return true;
        }

        private static bool canRead(string idPeople, ControlCondition condition, Dictionary<string, object> content)
        {
            bool _canRead = false;
            switch (condition.OperationType)
            {
                case OperationType.Or:
                    {
                        if (condition.ConditionList != null)
                        {
                            foreach (ControlCondition _condition in condition.ConditionList)
                            {
                                if (canRead(idPeople, _condition, content))
                                    return true;
                            }
                        }
                    }
                    break;
                case OperationType.And:
                    {
                        if (condition.ConditionList != null)
                        {
                            foreach (ControlCondition _condition in condition.ConditionList)
                            {
                                if (!canRead(idPeople, _condition, content))
                                    return false;
                            }
                            return true;
                        }
                    }
                    break;
                case OperationType.Person:
                    _canRead = condition.Values1.ValueType == ValueType.Arbitrary || condition.Values1 != null && condition.Values1.Value != null && idPeople == condition.Values1.Value.ToString();
                    break;
                case OperationType.Role:
                    {
                        int teamDefId = Convert.ToInt32(condition.Values1.Value);
                        int teamRoleId = Convert.ToInt32(condition.Values2.Value);
                        return Utils.HasExistTeamMember(teamDefId, teamRoleId, idPeople);
                    }
                case OperationType.Compare:
                    {
                        ConditionValue value1 = condition.Values1;
                        ConditionValue value2 = condition.Values2;
                        ConditionValue value3 = condition.Values3;
                        ConditionValue value4 = condition.Values4;
                        ConditionValue value5 = condition.Values5;

                        switch (value1.ValueType)
                        {
                            case Operation.ValueType.Constant:
                                {
                                    object val1 = condition.Values1.Value;
                                    switch (condition.Values2.ValueType)
                                    {
                                        case Operation.ValueType.Constant:
                                            return compareValues(val1, condition.Values2.Value, (CompareType)Enum.Parse(typeof(CompareType), condition.Values3.Value.ToString()), (ParamType)Enum.Parse(typeof(ParamType), condition.Values4.Value.ToString()));
                                        case Operation.ValueType.DocDef:
                                            {
                                                string field2 = condition.Values1.Value.ToString();
                                                object val2 = null;
                                                if (content != null && content.TryGetValue(field2, out val2))
                                                    return compareValues(val1, val2, (CompareType)Enum.Parse(typeof(CompareType), condition.Values3.Value.ToString()), (ParamType)Enum.Parse(typeof(ParamType), condition.Values4.Value.ToString()));
                                            }
                                            break;
                                    }
                                }
                                break;
                            case Operation.ValueType.DocDef:
                                {
                                    string field1 = condition.Values1.Value.ToString();
                                    object val1 = null;
                                    if (content != null && content.TryGetValue(field1, out val1))
                                    {
                                        switch (condition.Values2.ValueType)
                                        {
                                            case Operation.ValueType.Constant:
                                                return compareValues(val1, condition.Values2.Value, (CompareType)Enum.Parse(typeof(CompareType), condition.Values3.Value.ToString()), (ParamType)Enum.Parse(typeof(ParamType), condition.Values4.Value.ToString()));
                                            case Operation.ValueType.DocDef:
                                                {
                                                    string field2 = condition.Values1.Value.ToString();
                                                    object val2 = null;
                                                    if (content != null && content.TryGetValue(field2, out val2))
                                                        return compareValues(val1, val2, (CompareType)Enum.Parse(typeof(CompareType), condition.Values3.Value.ToString()), (ParamType)Enum.Parse(typeof(ParamType), condition.Values4.Value.ToString()));
                                                }
                                                break;
                                        }
                                    }
                                }
                                break;
                        }
                    }
                    break;
            }
            return _canRead;
        }
        #endregion
    }
}
